package com.ruoyi.framework.config;

import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.crazycake.shiro.IRedisManager;
import org.crazycake.shiro.RedisManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;

/**
 * redis配置
 *
 * @author ruoyi
 */
@Configuration
public class RedisConfig {

    public static final Logger log = LoggerFactory.getLogger(RedisConfig.class);

    // Redis
    @Value("${spring.redis.pool.max-active}")

    private int redisMaxActive;
    @Value("${spring.redis.pool.max-wait}")

    private int redisMaxWait;
    @Value("${spring.redis.pool.max-idle}")

    private int redisMaxIdle;

    @Value("${spring.redis.pool.min-idle}")
    private int redisMinIdle;

    @Value("${spring.redis.timeout}")
    private int redisTimeout;

    @Value("${spring.redis.testWhileIdle}")
    private boolean redisTestWhileIdle;

    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.redis.dict.host}")
    private String host;

    @Value("${spring.redis.dict.port}")
    private int port;

    @Value("${spring.redis.dict.password}")
    private String password;

    @Value("${spring.redis.common.host}")
    private String commonHost;

    @Value("${spring.redis.common.port}")
    private int commonPort;

    @Value("${spring.redis.common.password}")
    private String commonPassword;

    @Value("${spring.redis.ssdb.host}")
    private String ssdbHost;

    @Value("${spring.redis.ssdb.port}")
    private int ssdbPort;

    @Value("${spring.redis.ssdb.password}")
    private String ssdbPassword;

    @Bean(name = "redisConnectionFactory")
    @Primary
    public RedisConnectionFactory redisConnectionFactory() {

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
        redisStandaloneConfiguration.setPort(port);

        GenericObjectPoolConfig<JedisPoolConfig> poolConfig = new GenericObjectPoolConfig<JedisPoolConfig>();
        poolConfig.setMaxTotal(redisMaxActive);
        poolConfig.setMaxWaitMillis(redisMaxWait);
        poolConfig.setMaxIdle(redisMaxIdle);
        poolConfig.setMinIdle(redisMinIdle);
        poolConfig.setTestWhileIdle(redisTestWhileIdle);
        poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        poolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);

        log.info("redis pool config[{}]", poolConfig.toString());

        JedisClientConfiguration clientConfiguration = JedisClientConfiguration.builder().readTimeout(Duration.ZERO).connectTimeout(Duration.ZERO).usePooling().poolConfig(poolConfig).build();

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration, clientConfiguration);

        return jedisConnectionFactory;

    }

    @Bean(name = "dictRedisTemplate")
    @Primary
    public RedisTemplate<String, String> dictRedisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        return template;
    }

    @Bean(name = "commonRedisConnectionFactory")
    public RedisConnectionFactory commonRedisConnectionFactory() {

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(commonHost);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(commonPassword));
        redisStandaloneConfiguration.setPort(commonPort);

        GenericObjectPoolConfig<JedisPoolConfig> poolConfig = new GenericObjectPoolConfig<JedisPoolConfig>();
        poolConfig.setMaxTotal(redisMaxActive);
        poolConfig.setMaxWaitMillis(redisMaxWait);
        poolConfig.setMaxIdle(redisMaxIdle);
        poolConfig.setMinIdle(redisMinIdle);
        poolConfig.setTestWhileIdle(redisTestWhileIdle);
        poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        poolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);

        log.info("redis pool config[{}]", poolConfig.toString());

        JedisClientConfiguration clientConfiguration = JedisClientConfiguration.builder().readTimeout(Duration.ZERO).connectTimeout(Duration.ZERO).usePooling().poolConfig(poolConfig).build();

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration, clientConfiguration);

        return jedisConnectionFactory;

    }

    @Bean(name = "commonRedisTemplate")
    public RedisTemplate<String, String> commonRedisTemplate(@Qualifier("commonRedisConnectionFactory") RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        return template;
    }

    @Bean
    public IRedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(commonHost + ":" + commonPort);
        if (!StringUtils.isEmpty(commonPassword)) {
            redisManager.setPassword(commonPassword);
        }
        return redisManager;
    }

    @Bean(name = "ssdbConnectionFactory")
    public RedisConnectionFactory ssdbConnectionFactory() {

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(ssdbHost);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(ssdbPassword));
        redisStandaloneConfiguration.setPort(ssdbPort);

        GenericObjectPoolConfig<JedisPoolConfig> poolConfig = new GenericObjectPoolConfig<JedisPoolConfig>();
        poolConfig.setMaxTotal(redisMaxActive);
        poolConfig.setMaxWaitMillis(redisMaxWait);
        poolConfig.setMaxIdle(redisMaxIdle);
        poolConfig.setMinIdle(redisMinIdle);
        poolConfig.setTestWhileIdle(redisTestWhileIdle);
        poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        poolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);

        log.info("redis pool config[{}]", poolConfig.toString());

        JedisClientConfiguration clientConfiguration = JedisClientConfiguration.builder().readTimeout(Duration.ZERO).connectTimeout(Duration.ZERO).usePooling().poolConfig(poolConfig).build();

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration, clientConfiguration);

        return jedisConnectionFactory;

    }

    @Bean(name = "ssdbTemplate")
    public RedisTemplate<String, String> ssdbTemplate(@Qualifier("ssdbConnectionFactory") RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        return template;
    }
}
